Xbasic - OLE Automation - Implementing Callback Event Handlers in Xbasic

Description

This topic discusses how you can write Xbasic code to handle callback events when running OLE automation code.

For example, consider the following Xbasic code that uses the ADODB.CONNECTION object to connect to SQL server and then execute a SQL command.

dim adow as ADODBOleWrapper
dim conn as p = ole.create("adodb.connection" )
conn.Open("driver={SQL Server};server=LOCALHOST;database=Northwind")
conn.Execute("select * from customers")
conn.Close()

When this code executes, it will raise these events:

  • willconnect

  • connectcomplete

  • infomessage

  • willexecute

  • executecomplete

  • disconnect

In order to handle these events with Xbasic code you need to pass in an optional second argument to the ole.create() method. First, to get the function prototype for the event handlers you can use this method:

dim events as c 
events =  ole.Class_Event_Prototypes("adodb.connection")
showvar(events)

Once you have the function prototypes, you can create an Xbasic class using this pattern:

define class ADODBOleWrapper
'Your class code goes here

implementation EventHandler as OLE::A5Events
    'your Xbasic code to handle the callback functions goes here
end implementation

end class

Note that the class has a special 'implementation' section where the OLE callback handlers are defined. For example, let's create a real class that writes the name of the event that was raised to a property of the class (called 'traceEvents').

define class ADODBOleWrapper
dim traceEvents as c

function TraceEvent as v(event as c)
self.traceEvents = self.traceEvents + event
end function

implementation EventHandler as OLE::A5Events
function begintranscomplete as v(TransactionLevel as N,pError as a,adStatus as a,pConnection as p)
self.TraceEvent("begintranscomplete "+TransactionLevel+crlf())
end function

function committranscomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("committranscomplete "+crlf())
end function

function connectcomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("connectcomplete "+crlf())
end function

function disconnect as v(adStatus as a,pConnection as p)
self.TraceEvent("disconnect "+crlf())
end function

function executecomplete as v(RecordsAffected as N,pError as a,adStatus as a,pCommand as a,pRecordset as p,pConnection as p)
self.TraceEvent("executecomplete "+crlf())
end function

function infomessage as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("infomessage "+crlf())
end function

function rollbacktranscomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("rollbacktranscomplete "+crlf())
end function

function willconnect as v(ConnectionString as C,UserID as C,Password as C,Options as a,adStatus as a,pConnection as p)
self.TraceEvent("willconnect "+crlf())
end function

function willexecute as v(Source as C,CursorType as a,LockType as a,Options as a,adStatus as a,pCommand as p,pRecordset as p,pConnection as p)
self.TraceEvent("willexecute "+crlf())
end function

end implementation

end class

As you can see, this class defined a method called TraceEvent() which writes to the 'traceEvents' property of the class instance. In the Implementation section, the event handlers are all defined and they call the TraceEvent() method (using self.TraceEvent() ) to write the name of the event that was just fired to 'traceEvents' property of the class instance. Now, putting this all together, we can rewrite the OLE automation code as follows:

'DIM an instance of the class
dim adow as ADODBOleWrapper

'pass the class into the ole.create() call
dim conn as p = ole.create("adodb.connection" , adow )
conn.Open("driver={SQL Server};server=LOCALHOST;database=Northwind")
conn.Execute("select * from customers")
conn.Close()

'show the value of the class instance 'traceEvents' property
showvar( "Events " + crlf() +adow.traceEvents )

This next example is a different take on the previous example in which .open(), .execute() and .close() are implemented as methods of the class instance.

define class ADODBOleWrapper2
dim conn as p 
dim traceEvents as c

function TraceEvent as v(event as c)
self.traceEvents = self.traceEvents + event
end function

implementation EventHandler as OLE::A5Events
function begintranscomplete as v(TransactionLevel as N,pError as a,adStatus as a,pConnection as p)
self.TraceEvent("begintranscomplete "+TransactionLevel+crlf())
end function


function committranscomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("committranscomplete "+crlf())
end function


function connectcomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("connectcomplete "+crlf())
end function


function disconnect as v(adStatus as a,pConnection as p)
self.TraceEvent("disconnect "+crlf())
end function


function executecomplete as v(RecordsAffected as N,pError as a,adStatus as a,pCommand as a,pRecordset as p,pConnection as p)
self.TraceEvent("executecomplete "+crlf())
end function


function infomessage as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("infomessage "+crlf())
end function


function rollbacktranscomplete as v(pError as a,adStatus as a,pConnection as p)
self.TraceEvent("rollbacktranscomplete "+crlf())
end function


function willconnect as v(ConnectionString as C,UserID as C,Password as C,Options as a,adStatus as a,pConnection as p)
self.TraceEvent("willconnect "+crlf())
end function


function willexecute as v(Source as C,CursorType as a,LockType as a,Options as a,adStatus as a,pCommand as p,pRecordset as p,pConnection as p)
self.TraceEvent("willexecute "+crlf())
end function
function ping as v()
self.TraceEvent("PING "+crlf())
end function

end implementation

function adodbolewrapper2 as v ()
self.conn = ole.create("adodb.connection",self)
end function 

function Open as v( connectionString as c )
self.conn.Open(connectionString)
end function


function Execute as v( sqlStatement as c )
self.conn.Execute(sqlStatement)
end function


function Close as v( )
self.conn.Close()
end function
end class

To test this example:

'dim an instance of the class. this class has a constructor function
'which will execute when the class is dimmed
dim adow as ADODBOleWrapper2

'now call the methods of the class instance
adow.open("driver={SQL Server};server=localhost;database=Northwind")
adow.execute("select * from customers")
adow.close()

showvar( "Events "+crlf() + adow.traceEvents )